/**
 * Licensed Property to China UnionPay Co., Ltd.
 * <p>
 * (C) Copyright of China UnionPay Co., Ltd. 2010
 * All Rights Reserved.
 * <p>
 * <p>
 * Modification History:
 * =============================================================================
 * Author         Date          Description
 * ------------ ---------- ---------------------------------------------------
 * xshu       2014-05-28      MPI工具类
 * =============================================================================
 */
package com.unionpay.fsas.sdk.gm;

import java.security.PublicKey;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import com.unionpay.fsas.sdk.SDKConstants;
import com.unionpay.fsas.sdk.SDKUtil;
import com.unionpay.fsas.sdk.SecureUtil;

/**
 * @ClassName: GmCertUtil
 * @Description: fsassdk证书工具类，主要用于对证书的加载和使用
 *
 *  声明：以下代码只是为了方便机构测试而提供的样例代码，机构可以根据自己需要，按照技术文档编写。
 *  该代码仅供参考，不提供编码，性能，规范性等方面的保障<br>
 */
public class GmSDKUtil {

    private final static Logger logger = Logger.getLogger(GmSDKUtil.class);

    /**
     * 国密算法用。
     * 1. 按ascii排序。【注意不是字母顺序】
     * 2. 对1的结果sm3得到byte数组。
     * 3. 对2的结果用16进制小写字符串表示。【注意必须是小写】
     * 4. 对3的结果取byte数组。【注意不是16进制字符串转byte数组，而是当普通字符串转】
     * 5. 对4的结果用私钥算签名，算法为sm3withsm2。
     * 6. 对5的结果做base64，得到一个字符串就是签名。
     * @param data
     * @param certPath
     * @param certPwd
     * @param encoding
     * @return
     */
    public static String signSm2(Map<String, String> data, String certPath, String certPwd, String encoding) {
        try {
            // 将Map信息转换成key1=value1&key2=value2的形式
            String stringData = SDKUtil.coverMap2String(data);
            logger.info("打印排序后待签名请求报文串（交易返回11验证签名失败时可以用来同正确的进行比对）:[" + stringData + "]");
            logger.info("签名数据:[签名数据签名数据签名数据签名数据签名数据签名数据签名数据]");
            logger.info(stringData);
            byte[] sm3 = SecureUtil.sm3(stringData.getBytes(encoding));
            String sm3Hex = SecureUtil.byte2Hex(sm3).toLowerCase();
            logger.info("sm3结果（交易返回11验证签名失败可以用来同正确的进行比对）:[" + sm3Hex + "]");
            logger.info(sm3Hex);
            return Base64.encodeBase64String(GmUtil.signSm3WithSm2(sm3Hex.getBytes(encoding),
                    GmCertUtil.getCertIdByKeyStoreMap(certPath, certPwd).getBytes(encoding),
                    GmCertUtil.getSignCertPrivateKey(certPath, certPwd)));
        } catch (Exception e) {
            logger.error("calcSignRsa Error", e);
            return null;
        }
    }

    /**
     * 国密验签用。
     * @param resData
     * @param encoding
     * @return
     */
    public static boolean verifySm2(Map<String, String> resData, PublicKey pubKey, String encoding, String certId) {
        try {
            String stringSign = resData.remove(SDKConstants.param_signature);
            if (SDKUtil.isEmpty(stringSign)) {
                logger.error("signature is null. verifyRsa fail.");
                return false;
            }
            logger.info("签名原文：[" + stringSign + "]");
            String stringData = SDKUtil.coverMap2String(resData);
            logger.info("待验签排序串：[" + stringData + "]");
            byte[] sm3 = SecureUtil.sm3(stringData.getBytes(encoding));
            String sm3Hex = SecureUtil.byte2Hex(sm3).toLowerCase();
            logger.info("sm3结果:[" + sm3Hex + "]");
            return GmUtil.verifySm3WithSm2(sm3Hex.getBytes(encoding),
                    certId.getBytes(encoding),
                    Base64.decodeBase64(stringSign),
                    pubKey);
        } catch (Exception e) {
            logger.error("verifyRsa fail." + e.getMessage(), e);
            return false;
        }
    }

    public static boolean verifySm2N(Map<String, Object> resData, PublicKey pubKey, String encoding, String certId) {
        try {
            String stringSign = (String) resData.remove(SDKConstants.param_signature);
            if (SDKUtil.isEmpty(stringSign)) {
                logger.error("signature is null. verifyRsa fail.");
                return false;
            }
            logger.info("签名原文：[" + stringSign + "]");
            String stringData = SDKUtil.coverMap2StringNew(resData);
            logger.info("待验签排序串：[" + stringData + "]");
            byte[] sm3 = SecureUtil.sm3(stringData.getBytes(encoding));
            String sm3Hex = SecureUtil.byte2Hex(sm3).toLowerCase();
            logger.info("sm3结果:[" + sm3Hex + "]");
            return GmUtil.verifySm3WithSm2(sm3Hex.getBytes(encoding),
                    certId.getBytes(encoding),
                    Base64.decodeBase64(stringSign),
                    pubKey);
        } catch (Exception e) {
            logger.error("verifyRsa fail." + e.getMessage(), e);
            return false;
        }
    }

}
